/*
  @licstart The following is the entire license notice for the
  JavaScript code in this page.

  Copyright (C) 2015-2018  Emilia Blåsten emily@countermail.com

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.

  @licend The above is the entire license notice for the JavaScript code
  in this page.

  Contributions are welcome: https://notabug.org/emily/Lettus-CSS-MathJax
*/

// Use strict JavaScript mode
"use strict";

function loadMathJax(MJengine) {
  var engine = document.createElement("script");
  engine.type = "text/javascript";

  if(MJengine == "CDN") {
    engine.setAttribute("src", "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML");
  } else {
    // if using this one, configure lettus.css to the use appropriate url for the web fonts
    engine.setAttribute("src", "/MathJax/MathJax.js?config=TeX-MML-AM_CHTML");
  }

  // The MathJax.Hub.Queue will run after MathJax loaded everything
  engine.innerHTML = "MathJax.Hub.Queue(function() {" +
    "var theBody = document.getElementsByTagName('body')[0];" +
    "theBody.removeChild(document.getElementById('MJloading'));" +
    "setStaticFavicon();" +
    "document.getElementById('focusHere').scrollIntoView();" +
  "});";
  document.getElementsByTagName("head")[0].appendChild(engine);
};



loadMathJax("CDN"); // If use other than "CDN" then configure the web font URL in lettus.css
setAnimFavicon();
document.addEventListener("DOMContentLoaded", addBodyElements);
document.addEventListener("DOMContentLoaded", checkMissingIDs);
document.addEventListener("DOMContentLoaded", countersToNbr);
document.addEventListener("DOMContentLoaded", setNumbersAndLinks);
document.addEventListener("DOMContentLoaded", addAllLinksToFooter);
document.addEventListener("DOMContentLoaded", numberAllReferences);
document.addEventListener("DOMContentLoaded", displayCitationRefNbrs);

/*
Functions to set favicons
*/
function setAnimFavicon() {
  // stash old favicon
  var links = document.getElementsByTagName("link");
  var link, i;
  for(i=0; i < links.length; i++) {
    if(links[i].getAttribute("rel") && links[i].rel == "shortcut icon") {
      links[i].rel = "old shortcut icon";
      links[i].id = "old-favicon-link"
      link = document.createElement("link");
      link = links[i].cloneNode(true);
      links[i].parentNode.removeChild(links[i]);
      document.getElementsByTagName("head")[0].appendChild(link);
      break;
    }
  }

  // set animated favicon
  link = document.createElement("link");
  link.type = "image/gif";
  link.rel = "shortcut icon";
  link.href = "favicon-animated.gif";
  link.id = "favicon-link";
  document.getElementsByTagName("head")[0].appendChild(link);
};

function setStaticFavicon() {
  var ico, stashed, newIco;
  // remove the animated favicon
  ico = document.getElementById("favicon-link");
  ico.parentNode.removeChild(ico);

  // assumes the original favicon is in element with id "old-favicon-link"
  stashed = document.getElementById("old-favicon-link");
  newIco = document.createElement("link");
  if(stashed) {
    // restore the old one
    newIco = stashed.cloneNode(true);
    stashed.parentNode.removeChild(stashed);
  } else {
    // create an empty transparent one using ImageMagick and base64:
    // "convert -size 16x16 xc:black -transparent black try.gif"
    // "base64 try.gif" and then you see the binary encoding in the terminal.
    newIco.href = "data:image/gif;base64," +
      "R0lGODlhEAAQAPAAAAAAAAAAACH5BAEAAAAALA" +
      "AAAAAQABAAAAIOhI+py+0Po5y02ouzPgUAOw==";
    newIco.type = "image/gif";
  }
  newIco.rel = "shortcut icon";
  newIco.id = "favicon-link";
  document.getElementsByTagName("head")[0].appendChild(newIco);
};


/*
Function to set the background "MathJax typesetting..." text right after
the DOM has been loaded.
*/
function addBodyElements() {
  var theBody = document.getElementsByTagName("body")[0];
  var bg, anim;  //background + animation
  var theFoot; //Footer

  // MathJax loading background
  bg = document.createElement("div");
  bg.id = "MJloading";
  bg.innerHTML = "MathJax<br>typesetting...";
  // an animated child node
  anim = document.createElement("span");
  anim.id = "anim1";
  anim.innerHTML = "+";
  bg.appendChild(anim);
  theBody.insertBefore(bg, theBody.firstChild);

  // Footer containig reference list
  if(!document.getElementById("bibliography")) {
    theFoot = document.createElement("footer");
    theFoot.id = "bibliography";
    theFoot.innerHTML = "<h2>References</h2>";
    theBody.appendChild(theFoot);
  } else
    console.log("The bibliography already exists, typed in manually?");
};


/*
Functions to be run when the DOM tree has been loaded. Sets the "Theorem
X. " text in front of theorem divs, etc. Also prepends "Lemma Y" to the
text in links pointing to theorems, lemmas, etc. Also checks for missing
link targets.
*/
function checkMissingIDs() {
  var i, iMax;
  var links, linksTo;

  links = document.getElementsByTagName("a");
  iMax = links.length;
  for(i=0; i < iMax; i++) {
    linksTo = links[i].getAttribute("href");
    if(linksTo.substring(0,1) == "#") {
      if(document.getElementById(linksTo.substring(1,linksTo.length)) === null) {
        alert("Link " + linksTo + " missing target.");
      }
    }
  }
};



function countersToNbr() {
  var cntr1 = 0;
  var cntr2 = 0;
  var cntr3 = 0;

  var elems = document.querySelectorAll("[data-counters]");
  var i, iMax = elems.length, nbr = "";
  for(i = 0; i < iMax; i++) {
    switch(elems[i].getAttribute("data-counters")) {
      case "1":
        nbr = "" + (++cntr1);
        cntr2 = 0;
        cntr3 = 0;
        break;
      case "2":
        nbr = "" + cntr1 + "." + (++cntr2);
        cntr3 = 0;
        break;
      case "3":
        nbr = "" + cntr1 + "." + cntr2 + "." + (++cntr3);
        break;
      default:
        console.log('Attribute "data-counters" must be either "1", "2" or "3".');
    }
    elems[i].setAttribute("data-nbr", nbr);
  }
};




function setNumbersAndLinks() {
  var beforeElements = [
    ["theorem", "Theorem"],
    ["lemma", "Lemma"],
    ["corollary", "Corollary"],
    ["proposition", "Proposition"],
    ["conjecture", "Conjecture"],
    ["definition", "Definition"],
    ["remark", "Remark"],
    ["proof", "Proof"],
    ["motivation", "Motivation"]
  ];

  var name, fullName, getsNbr, titleSpan;
  var divs = document.getElementsByTagName("div");

  var i, j;

  // Get the data structure
  for(i=0; i < divs.length; i++) {
    if(!divs[i].className) continue;
    for(j=0; j < beforeElements.length; j++) {
      if(divs[i].className.indexOf(beforeElements[j][0]) == -1)
        continue;
      // Now we know that it has one of the classes of interest
      // Place the number in its name only from the data-nbr attribute
      getsNbr = divs[i].getAttribute("data-nbr") != null;
      name = beforeElements[j][1] + ((getsNbr) ? " " + divs[i].getAttribute("data-nbr") : ""),
      fullName = document.createElement("span")
      fullName.className = beforeElements[j][0];
      // Check if the div has a title (e.g. theorem name)
      if(divs[i].title) {
        titleSpan = document.createElement("span");
        titleSpan.innerHTML = "(" + divs[i].title + ")";
        titleSpan.className = "theoremName";
        fullName.innerHTML = name + " ";
        fullName.appendChild(titleSpan);
        fullName.innerHTML += ". ";
      } else {
        fullName.innerHTML = name + ". ";
      }
      // Link the name to the div if it has an ID
      if(divs[i].id) {
        fullName.innerHTML = "<a href='\#" + divs[i].id + 
        "'class='addTxtForbidden'>" + fullName.innerHTML + "</a>";
      }
      // Show the name in front of the result div
      if(divs[i].firstChild)
        divs[i].insertBefore(fullName, divs[i].firstChild);
      else
        divs[i].appendChild(fullName);
      // If already done for this div, then go to next div
      break;
    }
  }
  // Add result numbers to links refering to them from same file
  displayInArticleReferenceNbrs();
};




function listOutsideWebsitesLinkedTo() {
  var sourcesLinkedTo = [];
  var links, linksTo, i;

  links = document.getElementsByTagName("a");
  for(i=0; i < links.length; i++) {
    linksTo = links[i].getAttribute("href");
    // remove anything after a '#'
    if(linksTo.indexOf("#") > -1)
      linksTo = linksTo.slice(0,linksTo.indexOf("#"));
    // Add to list if not yet added and points outside
    if( linksTo.length > 0 &&
        sourcesLinkedTo.indexOf(linksTo) == -1 &&
        linksTo.substring(0,1) != "#") {
      sourcesLinkedTo.push(linksTo);
    }
  }
  return sourcesLinkedTo.sort();
};



function addAllLinksToFooter() {
  // set reference list to footer
  var theFoot;
  var onlineRefsHeader, onlineList;
  var targets = listOutsideWebsitesLinkedTo();
  var ref, i, item;

  theFoot = document.getElementById("bibliography");
  onlineRefsHeader = document.createElement("h3");
  onlineRefsHeader.innerHTML = "Links";
  theFoot.appendChild(onlineRefsHeader);
  onlineList = document.createElement("ul");
  onlineList.setAttribute("class", "referenceList");
  for(i = 0; i < targets.length; i++) {
    ref = document.createElement("a");
    ref.setAttribute("href", targets[i]);
    ref.classList.add("addTxtForbidden");
    ref.innerHTML = targets[i];
    item = document.createElement("li");
    item.setAttribute("class", "reference");
    item.appendChild(ref);
    onlineList.appendChild(item);
  }
  theFoot.appendChild(onlineList);
};



function numberAllReferences() {
  var refs = document.getElementsByClassName("reference");
  var i, refNbr;

  for(i = 0; i < refs.length; i++) {
    refNbr = document.createElement("span");
    refNbr.setAttribute("class", "ref-nbr");
    refNbr.innerHTML = "[" + (i+1) + "] ";
    refs[i].insertBefore(refNbr, refs[i].firstChild);
    refs[i].setAttribute("data-refnumber", i+1);
  }
};




function displayInArticleReferenceNbrs() {
  var links = document.getElementsByTagName("a");
  var i, iMax;
  var linkTo, elem, nBr;
  iMax = links.length;
  // Loop through all links and check if the ID they point to exists
  for(i = 0; i < iMax; i++) {
    nBr = null;
    // just using link[i].herf will give "file://.........#thm1"
    linkTo = links[i].getAttribute("href");
    if(linkTo.substring(0,1) != "#" || links[i].classList.contains("addTxtForbidden"))
      continue;
    // Now links[i] points to this document and accepts displaying a number
    elem = document.getElementById(linkTo.substring(1,linkTo.length));
    if(elem !== null)
      nBr = elem.getAttribute("data-nbr");
    if(nBr !== null)
      links[i].innerHTML += nBr ? " " + nBr : "";
  }
};


function displayCitationRefNbrs() {
  var links = document.getElementsByTagName("a");
  var refs = document.getElementsByClassName("reference");
  var i, iMax = links.length;
  var j, jMax = refs.length;
  var linkTo, refNbr;
  var refAnchor;
  for(i = 0; i < iMax; i++) {
    if(links[i].classList.contains("addTxtForbidden"))
      continue;
    linkTo = links[i].getAttribute("href");
    for(j = 0; j < jMax; j++) {
      refAnchor = refs[j].getElementsByTagName("a")[0];
      if( // 1st case: cites this document using #ID
          (linkTo.substring(0,1) == "#" && linkTo == "#" + refs[j].id) ||
          // 2nd case: cites outside URL without #ID in href
          (typeof refAnchor != "undefined" &&
          linkTo.indexOf("#") == -1 &&
          refAnchor.getAttribute("href") == linkTo) ) {
        refNbr = document.createElement("span");
        refNbr.setAttribute("class", "ref-nbr");
        refNbr.innerHTML = " [" + refs[j].getAttribute("data-refnumber");
        // If linking to item in reference list, then put innerHTML inside [ ]
        if(links[i].innerHTML && linkTo.substring(0,1)=="#") {
          refNbr.innerHTML += ", " + links[i].innerHTML;
          links[i].innerHTML = "";
        }
        refNbr.innerHTML += "]";
        links[i].appendChild(refNbr);
        break;
      }
      if( //3rd case: cites outside URL with #ID in href
          typeof refAnchor != "undefined" &&
          linkTo.indexOf("#") > -1 &&
          refAnchor.getAttribute("href") == linkTo.slice(0,linkTo.indexOf("#")) ) {
        refNbr = document.createElement("span");
        refNbr.setAttribute("class", "ref-nbr");
        refNbr.innerHTML = " [" + refs[j].getAttribute("data-refnumber") + ", "
          + linkTo.slice(linkTo.indexOf("#"),linkTo.length) + "]";
        links[i].appendChild(refNbr);
        break;
      }
    }
  }
};




